home *** CD-ROM | disk | FTP | other *** search
/ InterCD 2000 September / september_2000.iso / intercd / root / ^Linux / WindowMaker / util / wmsetbg.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-03-19  |  33.3 KB  |  1,474 lines

  1. /* wmsetbg.c- sets root window background image and also works as
  2.  *         workspace background setting helper for wmaker
  3.  *
  4.  *  WindowMaker window manager
  5.  * 
  6.  *  Copyright (c) 1998, 1999 Alfredo K. Kojima
  7.  *  Copyright (c) 1998 Dan Pascu
  8.  * 
  9.  *  This program is free software; you can redistribute it and/or modify
  10.  *  it under the terms of the GNU General Public License as published by
  11.  *  the Free Software Foundation; either version 2 of the License, or
  12.  *  (at your option) any later version.
  13.  *
  14.  *  This program is distributed in the hope that it will be useful,
  15.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  16.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17.  *  GNU General Public License for more details.
  18.  *
  19.  *  You should have received a copy of the GNU General Public License
  20.  *  along with this program; if not, write to the Free Software
  21.  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 
  22.  *  USA.
  23.  */
  24.  
  25. /*
  26.  * TODO: rewrite, too dirty
  27.  */
  28.  
  29. #include <stdio.h>
  30. #include <stdlib.h>
  31. #include <unistd.h>
  32. #include <X11/Xlib.h>
  33. #include <X11/Xutil.h>
  34. #include <X11/Xatom.h>
  35. #include <string.h>
  36. #include <pwd.h>
  37. #include <signal.h>
  38. #include <sys/types.h>
  39. #include <ctype.h>
  40.  
  41. #include "../src/config.h"
  42.  
  43. #ifdef HAVE_DLFCN_H
  44. #include <dlfcn.h>
  45. #endif
  46.  
  47. #include "../src/wconfig.h"
  48.  
  49. #include <WINGs.h>
  50. #include <wraster.h>
  51.  
  52. #include <proplist.h>
  53.  
  54. #define PROG_VERSION    "wmsetbg (Window Maker) 2.6"
  55.  
  56.  
  57. #define WORKSPACE_COUNT (MAX_WORKSPACES+1)
  58.  
  59.  
  60. Display *dpy;
  61. char *display = "";
  62. Window root;
  63. int scr;
  64. int scrWidth;
  65. int scrHeight;
  66.  
  67.  
  68. Bool smooth = False;
  69.  
  70.  
  71. Pixmap CurrentPixmap = None;
  72. char *PixmapPath = NULL;
  73.  
  74.  
  75. extern Pixmap LoadJPEG(RContext *rc, char *file_name, int *width, int *height);
  76.  
  77.  
  78. typedef struct BackgroundTexture {
  79.     int refcount;
  80.  
  81.     int solid;
  82.  
  83.     char *spec;
  84.  
  85.     XColor color;
  86.     Pixmap pixmap;               /* for all textures, including solid */
  87.     int width;                   /* size of the pixmap */
  88.     int height;
  89. } BackgroundTexture;
  90.  
  91.  
  92.  
  93. RImage*
  94. loadImage(RContext *rc, char *file)
  95. {
  96.     char *path;
  97.     RImage *image;
  98.  
  99.     if (access(file, F_OK)!=0) {
  100.     path = wfindfile(PixmapPath, file);
  101.     if (!path) {
  102.         wwarning("%s:could not find image file used in texture", file);
  103.         return NULL;
  104.     }
  105.     } else {
  106.     path = wstrdup(file);
  107.     }
  108.  
  109.     image = RLoadImage(rc, path, 0);
  110.     if (!image) {
  111.     wwarning("%s:could not load image file used in texture:%s", path,
  112.          RMessageForError(RErrorCode));
  113.     }
  114.     free(path);
  115.  
  116.     return image;
  117. }
  118.  
  119.  
  120. BackgroundTexture*
  121. parseTexture(RContext *rc, char *text)
  122. {
  123.     BackgroundTexture *texture = NULL;
  124.     proplist_t texarray;
  125.     proplist_t val;
  126.     int count;
  127.     char *tmp;
  128.     char *type;
  129.  
  130. #define GETSTRORGOTO(val, str, i, label) \
  131.         val = PLGetArrayElement(texarray, i);\
  132.         if (!PLIsString(val)) {\
  133.             wwarning("could not parse texture %s", text);\
  134.             goto label;\
  135.         }\
  136.         str = PLGetString(val)
  137.  
  138.     texarray = PLGetProplistWithDescription(text);
  139.     if (!texarray || !PLIsArray(texarray) 
  140.     || (count = PLGetNumberOfElements(texarray)) < 2) {
  141.  
  142.     wwarning("could not parse texture %s", text);
  143.     if (texarray)
  144.         PLRelease(texarray);
  145.     return NULL;
  146.     }
  147.  
  148.     texture = wmalloc(sizeof(BackgroundTexture));
  149.     memset(texture, 0, sizeof(BackgroundTexture));
  150.  
  151.     GETSTRORGOTO(val, type, 0, error);
  152.  
  153.     if (strcasecmp(type, "solid")==0) {
  154.     XColor color;
  155.     Pixmap pixmap;
  156.  
  157.     texture->solid = 1;
  158.     
  159.     GETSTRORGOTO(val, tmp, 1, error);
  160.  
  161.     if (!XParseColor(dpy, DefaultColormap(dpy, scr), tmp, &color)) {
  162.         wwarning("could not parse color %s in texture %s", tmp, text);
  163.         goto error;
  164.     }
  165.     XAllocColor(dpy, DefaultColormap(dpy, scr), &color);
  166.  
  167.     pixmap = XCreatePixmap(dpy, root, 8, 8, DefaultDepth(dpy, scr));
  168.     XSetForeground(dpy, DefaultGC(dpy, scr), color.pixel);
  169.     XFillRectangle(dpy, pixmap, DefaultGC(dpy, scr), 0, 0, 8, 8);
  170.  
  171.     texture->pixmap = pixmap;
  172.     texture->color = color;
  173.     texture->width = 8;
  174.     texture->height = 8;
  175.     } else if (strcasecmp(type, "vgradient")==0
  176.            || strcasecmp(type, "dgradient")==0
  177.            || strcasecmp(type, "hgradient")==0) {
  178.     XColor color;
  179.     RColor color1, color2;
  180.     RImage *image;
  181.     Pixmap pixmap;
  182.     int gtype;
  183.     int iwidth, iheight;
  184.  
  185.     GETSTRORGOTO(val, tmp, 1, error);
  186.  
  187.     if (!XParseColor(dpy, DefaultColormap(dpy, scr), tmp, &color)) {
  188.         wwarning("could not parse color %s in texture %s", tmp, text);
  189.         goto error;
  190.     }
  191.  
  192.     color1.red = color.red >> 8;
  193.     color1.green = color.green >> 8;
  194.     color1.blue = color.blue >> 8;
  195.  
  196.     GETSTRORGOTO(val, tmp, 2, error);
  197.  
  198.     if (!XParseColor(dpy, DefaultColormap(dpy, scr), tmp, &color)) {
  199.         wwarning("could not parse color %s in texture %s", tmp, text);
  200.         goto error;
  201.     }
  202.  
  203.     color2.red = color.red >> 8;
  204.     color2.green = color.green >> 8;
  205.     color2.blue = color.blue >> 8;
  206.  
  207.     switch (type[0]) {
  208.      case 'h':
  209.      case 'H':
  210.         gtype = RHorizontalGradient;
  211.         iwidth = scrWidth;
  212.         iheight = 8;
  213.         break;
  214.      case 'V':
  215.      case 'v':
  216.         gtype = RVerticalGradient;
  217.         iwidth = 8;
  218.         iheight = scrHeight;
  219.         break;
  220.      default:
  221.         gtype = RDiagonalGradient;
  222.         iwidth = scrWidth;
  223.         iheight = scrHeight;
  224.         break;
  225.     }
  226.  
  227.     image = RRenderGradient(iwidth, iheight, &color1, &color2, gtype);
  228.  
  229.     if (!image) {
  230.         wwarning("could not render gradient texture:%s",
  231.              RMessageForError(RErrorCode));
  232.         goto error;
  233.     }
  234.  
  235.     if (!RConvertImage(rc, image, &pixmap)) {
  236.         wwarning("could not convert texture:%s", 
  237.              RMessageForError(RErrorCode));
  238.         RDestroyImage(image);
  239.         goto error;
  240.     }
  241.  
  242.     texture->width = image->width;
  243.     texture->height = image->height;
  244.     RDestroyImage(image);
  245.  
  246.     texture->pixmap = pixmap;
  247.     } else if (strcasecmp(type, "mvgradient")==0
  248.            || strcasecmp(type, "mdgradient")==0
  249.            || strcasecmp(type, "mhgradient")==0) {
  250.     XColor color;
  251.     RColor **colors;
  252.     RImage *image;
  253.     Pixmap pixmap;
  254.     int i, j;
  255.     int gtype;
  256.     int iwidth, iheight;
  257.  
  258.     colors = malloc(sizeof(RColor*)*(count-1));
  259.     if (!colors) {
  260.         wwarning("out of memory while parsing texture");
  261.         goto error;
  262.     }
  263.     memset(colors, 0, sizeof(RColor*)*(count-1));
  264.  
  265.     for (i = 2; i < count; i++) {
  266.         val = PLGetArrayElement(texarray, i);
  267.         if (!PLIsString(val)) {
  268.         wwarning("could not parse texture %s", text);
  269.  
  270.         for (j = 0; colors[j]!=NULL; j++)
  271.             free(colors[j]);
  272.         free(colors);
  273.         goto error;
  274.         }
  275.         tmp = PLGetString(val);
  276.  
  277.         if (!XParseColor(dpy, DefaultColormap(dpy, scr), tmp, &color)) {
  278.         wwarning("could not parse color %s in texture %s",
  279.              tmp, text);
  280.  
  281.         for (j = 0; colors[j]!=NULL; j++)
  282.             free(colors[j]);
  283.         free(colors);
  284.         goto error;
  285.         }
  286.         if (!(colors[i-2] = malloc(sizeof(RColor)))) {
  287.         wwarning("out of memory while parsing texture");
  288.  
  289.         for (j = 0; colors[j]!=NULL; j++)
  290.             free(colors[j]);
  291.         free(colors);
  292.         goto error;
  293.         }
  294.  
  295.         colors[i-2]->red = color.red >> 8;
  296.         colors[i-2]->green = color.green >> 8;
  297.         colors[i-2]->blue = color.blue >> 8;
  298.     }
  299.  
  300.     switch (type[1]) {
  301.      case 'h':
  302.      case 'H':
  303.         gtype = RHorizontalGradient;
  304.         iwidth = scrWidth;
  305.         iheight = 8;
  306.         break;
  307.      case 'V':
  308.      case 'v':
  309.         gtype = RVerticalGradient;
  310.         iwidth = 8;
  311.         iheight = scrHeight;
  312.         break;
  313.      default:
  314.         gtype = RDiagonalGradient;
  315.         iwidth = scrWidth;
  316.         iheight = scrHeight;
  317.         break;
  318.     }
  319.  
  320.     image = RRenderMultiGradient(iwidth, iheight, colors, gtype);
  321.     
  322.     for (j = 0; colors[j]!=NULL; j++)
  323.         free(colors[j]);
  324.     free(colors);
  325.  
  326.     if (!image) {
  327.         wwarning("could not render gradient texture:%s",
  328.              RMessageForError(RErrorCode));
  329.         goto error;
  330.     }
  331.  
  332.     if (!RConvertImage(rc, image, &pixmap)) {
  333.         wwarning("could not convert texture:%s", 
  334.              RMessageForError(RErrorCode));
  335.         RDestroyImage(image);
  336.         goto error;
  337.     }
  338.  
  339.     texture->width = image->width;
  340.     texture->height = image->height;
  341.     RDestroyImage(image);
  342.  
  343.     texture->pixmap = pixmap;
  344.     } else if (strcasecmp(type, "cpixmap")==0
  345.       || strcasecmp(type, "spixmap")==0
  346.       || strcasecmp(type, "mpixmap")==0
  347.       || strcasecmp(type, "tpixmap")==0) {
  348.     XColor color;
  349.     Pixmap pixmap = None;
  350.     RImage *image = NULL;
  351.     int w, h;
  352.     int iwidth, iheight;
  353.     RColor rcolor;
  354.  
  355.  
  356.     GETSTRORGOTO(val, tmp, 1, error);
  357. /*
  358.     if (toupper(type[0]) == 'T' || toupper(type[0]) == 'C')
  359.         pixmap = LoadJPEG(rc, tmp, &iwidth, &iheight);
  360.  */
  361.  
  362.     if (!pixmap) {
  363.         image = loadImage(rc, tmp);
  364.         if (!image) {
  365.         goto error;
  366.         }
  367.         iwidth = image->width;
  368.         iheight = image->height;
  369.     }
  370.  
  371.     GETSTRORGOTO(val, tmp, 2, error);
  372.  
  373.     if (!XParseColor(dpy, DefaultColormap(dpy, scr), tmp, &color)) {
  374.         wwarning("could not parse color %s in texture %s\n", tmp, text);
  375.         RDestroyImage(image);
  376.         goto error;
  377.     }
  378.     if (!XAllocColor(dpy, DefaultColormap(dpy, scr), &color)) {
  379.         rcolor.red = color.red >> 8;
  380.         rcolor.green = color.green >> 8;
  381.         rcolor.blue = color.blue >> 8;
  382.         RGetClosestXColor(rc, &rcolor, &color);
  383.     } else {
  384.         rcolor.red = 0;
  385.         rcolor.green = 0;
  386.         rcolor.blue = 0;
  387.     }
  388.     /* for images with a transparent color */
  389.     if (image->data[3]) {
  390.         RCombineImageWithColor(image, &rcolor);
  391.     }
  392.  
  393.     switch (toupper(type[0])) {
  394.      case 'T':
  395.         texture->width = iwidth;
  396.         texture->height = iheight;
  397.         if (!pixmap && !RConvertImage(rc, image, &pixmap)) {
  398.         wwarning("could not convert texture:%s", 
  399.              RMessageForError(RErrorCode));
  400.         RDestroyImage(image);
  401.         goto error;
  402.         }
  403.         if (image)
  404.         RDestroyImage(image);
  405.         break;
  406.      case 'S':
  407.      case 'M':
  408.         if (toupper(type[0])=='S') {
  409.         w = scrWidth;
  410.         h = scrHeight;
  411.         } else {
  412.         if (iwidth*scrHeight > iheight*scrWidth) {
  413.             w = scrWidth;
  414.             h = (scrWidth*iheight)/iwidth;
  415.         } else {
  416.             h = scrHeight;
  417.             w = (scrHeight*iwidth)/iheight;
  418.         }
  419.         }
  420.         if (w != image->width || h != image->height) {
  421.         RImage *simage;
  422.  
  423.         if (smooth)
  424.             simage = RSmoothScaleImage(image, w, h);
  425.         else
  426.             simage = RScaleImage(image, w, h);
  427.         if (!simage) {
  428.             wwarning("could not scale image:%s", 
  429.                  RMessageForError(RErrorCode));
  430.             RDestroyImage(image);
  431.             goto error;
  432.         }
  433.         RDestroyImage(image);
  434.         image = simage;
  435.         }
  436.         iwidth = image->width;
  437.         iheight = image->height;
  438.  
  439.         /* fall through */
  440.      case 'C':
  441.         {
  442.         Pixmap cpixmap;
  443.  
  444.         if (!pixmap && !RConvertImage(rc, image, &pixmap)) {
  445.             wwarning("could not convert texture:%s", 
  446.                  RMessageForError(RErrorCode));
  447.             RDestroyImage(image);
  448.             goto error;
  449.         }
  450.  
  451.         if (iwidth != scrWidth || iheight != scrHeight) {
  452.             int x, y, sx, sy, w, h;
  453.  
  454.             cpixmap = XCreatePixmap(dpy, root, scrWidth, scrHeight,
  455.                         DefaultDepth(dpy, scr));
  456.  
  457.             XSetForeground(dpy, DefaultGC(dpy, scr), color.pixel);
  458.             XFillRectangle(dpy, cpixmap, DefaultGC(dpy, scr),
  459.                    0, 0, scrWidth, scrHeight);
  460.  
  461.             if (iheight < scrHeight) {
  462.             h = iheight;
  463.             y = (scrHeight - h)/2;
  464.             sy = 0;
  465.             } else {
  466.             sy = (iheight - scrHeight)/2;
  467.             y = 0;
  468.             h = scrHeight;
  469.             }
  470.             if (iwidth < scrWidth) {
  471.             w = iwidth;
  472.             x = (scrWidth - w)/2;
  473.             sx = 0;
  474.             } else {
  475.             sx = (iwidth - scrWidth)/2;
  476.             x = 0;
  477.             w = scrWidth;
  478.             }
  479.  
  480.             XCopyArea(dpy, pixmap, cpixmap, DefaultGC(dpy, scr),
  481.                   sx, sy, w, h, x, y);
  482.             XFreePixmap(dpy, pixmap);
  483.             pixmap = cpixmap;
  484.         }
  485.         if (image)
  486.             RDestroyImage(image);
  487.  
  488.         texture->width = scrWidth;
  489.         texture->height = scrHeight;
  490.         }
  491.         break;
  492.     }
  493.  
  494.     texture->pixmap = pixmap;
  495.     texture->color = color;
  496.     } else if (strcasecmp(type, "thgradient")==0
  497.            || strcasecmp(type, "tvgradient")==0
  498.            || strcasecmp(type, "tdgradient")==0) {
  499.     XColor color;
  500.     RColor color1, color2;
  501.     RImage *image;
  502.     RImage *gradient;
  503.     RImage *tiled;
  504.     Pixmap pixmap;
  505.     int opaq;
  506.     char *file;
  507.     int gtype;
  508.     int twidth, theight;
  509.  
  510.     GETSTRORGOTO(val, file, 1, error);
  511.  
  512.     GETSTRORGOTO(val, tmp, 2, error);
  513.  
  514.     opaq = atoi(tmp);
  515.  
  516.     GETSTRORGOTO(val, tmp, 3, error);
  517.  
  518.     if (!XParseColor(dpy, DefaultColormap(dpy, scr), tmp, &color)) {
  519.         wwarning("could not parse color %s in texture %s", tmp, text);
  520.         goto error;
  521.     }
  522.  
  523.     color1.red = color.red >> 8;
  524.     color1.green = color.green >> 8;
  525.     color1.blue = color.blue >> 8;
  526.  
  527.     GETSTRORGOTO(val, tmp, 4, error);
  528.  
  529.     if (!XParseColor(dpy, DefaultColormap(dpy, scr), tmp, &color)) {
  530.         wwarning("could not parse color %s in texture %s", tmp, text);
  531.         goto error;
  532.     }
  533.  
  534.     color2.red = color.red >> 8;
  535.     color2.green = color.green >> 8;
  536.     color2.blue = color.blue >> 8;
  537.  
  538.     image = loadImage(rc, file);
  539.     if (!image) {
  540.         goto error;
  541.     }
  542.  
  543.     switch (type[1]) {
  544.      case 'h':
  545.      case 'H':
  546.         gtype = RHorizontalGradient;
  547.         twidth = scrWidth;
  548.         theight = image->height > scrHeight ? scrHeight : image->height;
  549.         break;
  550.      case 'V':
  551.      case 'v':
  552.         gtype = RVerticalGradient;
  553.         twidth = image->width > scrWidth ? scrWidth : image->width;
  554.         theight = scrHeight;
  555.         break;
  556.      default:
  557.         gtype = RDiagonalGradient;
  558.         twidth = scrWidth;
  559.         theight = scrHeight;
  560.         break;
  561.     }
  562.     gradient = RRenderGradient(twidth, theight, &color1, &color2, gtype);
  563.  
  564.     if (!gradient) {
  565.         wwarning("could not render texture:%s",
  566.              RMessageForError(RErrorCode));
  567.             RDestroyImage(gradient);
  568.             RDestroyImage(image);
  569.         goto error;
  570.     }
  571.  
  572.     tiled = RMakeTiledImage(image, twidth, theight);
  573.     if (!tiled) {
  574.         wwarning("could not render texture:%s",
  575.              RMessageForError(RErrorCode));
  576.         RDestroyImage(gradient);
  577.         RDestroyImage(image);
  578.         goto error;
  579.     }
  580.     RDestroyImage(image);
  581.  
  582.     RCombineImagesWithOpaqueness(tiled, gradient, opaq);
  583.     RDestroyImage(gradient);
  584.  
  585.     if (!RConvertImage(rc, tiled, &pixmap)) {
  586.         wwarning("could not convert texture:%s", 
  587.              RMessageForError(RErrorCode));
  588.         RDestroyImage(tiled);
  589.         goto error;
  590.     }
  591.     texture->width = tiled->width;
  592.     texture->height = tiled->height;
  593.  
  594.     RDestroyImage(tiled);
  595.  
  596.     texture->pixmap = pixmap;    
  597.     } else if (strcasecmp(type, "function")==0) {
  598. #ifdef HAVE_DLFCN_H
  599.     void (*initFunc) (Display*, Colormap);
  600.     RImage* (*mainFunc) (int, char**, int, int, int);
  601.     Pixmap pixmap;
  602.     RImage *image = 0;
  603.     int success = 0;
  604.     char *lib, *func, **argv = 0;
  605.     void *handle = 0;
  606.     int i, argc;
  607.  
  608.         if (count < 3)
  609.         goto function_cleanup;
  610.  
  611.     /* get the library name */
  612.     GETSTRORGOTO(val, lib, 1, function_cleanup);
  613.  
  614.     /* get the function name */
  615.     GETSTRORGOTO(val, func, 2, function_cleanup);
  616.  
  617.     argc = count - 2;
  618.     argv = (char**)wmalloc(argc * sizeof(char*));
  619.  
  620.     /* get the parameters */
  621.     argv[0] = func;
  622.     for (i=0; i<argc-1; i++) {
  623.         GETSTRORGOTO(val, tmp, 3+i, function_cleanup);
  624.         argv[i+1] = wstrdup(tmp);
  625.     }
  626.  
  627.     handle = dlopen(lib, RTLD_LAZY);
  628.     if (!handle) {
  629.             wwarning("could not find library %s", lib);
  630.         goto function_cleanup;
  631.     }
  632.  
  633.     initFunc = dlsym(handle, "initWindowMaker");
  634.         if (!initFunc) {
  635.         wwarning("could not initialize library %s", lib);
  636.         goto function_cleanup;
  637.         }
  638.         initFunc(dpy, DefaultColormap(dpy, scr));
  639.  
  640.         mainFunc = dlsym(handle, func);
  641.         if (!mainFunc) {
  642.             wwarning("could not find function %s::%s", lib, func);
  643.         goto function_cleanup;
  644.         }
  645.         image = mainFunc(argc, argv, scrWidth, scrHeight, 0);
  646.  
  647.         if (!RConvertImage(rc, image, &pixmap)) {
  648.         wwarning("could not convert texture:%s", 
  649.             RMessageForError(RErrorCode));
  650.         goto function_cleanup;
  651.     }
  652.     texture->width = scrWidth;
  653.         texture->height = scrHeight;
  654.     texture->pixmap = pixmap;    
  655.         success = 1;
  656.  
  657. function_cleanup:
  658.         if (argv) {
  659.         int i;
  660.         for (i=0; i<argc; i++) {
  661.             free(argv[i]);
  662.         }
  663.     }
  664.     if (handle) {
  665.         dlclose(handle);
  666.     }
  667.     if (image) {
  668.             RDestroyImage(image);
  669.     }
  670.     if (!success) {
  671.         goto error;
  672.     }
  673. #else
  674.     wwarning("function textures not supported");
  675.     goto error;
  676. #endif
  677.     } else {
  678.     wwarning("invalid texture type %s", text);
  679.     goto error;
  680.     }
  681.  
  682.     texture->spec = wstrdup(text);
  683.  
  684.     return texture;
  685.  
  686. error:
  687.     if (texture)
  688.     free(texture);
  689.     if (texarray)
  690.     PLRelease(texarray);
  691.  
  692.     return NULL;
  693. }
  694.  
  695.  
  696. void
  697. freeTexture(BackgroundTexture *texture)
  698. {
  699.     if (texture->solid) {
  700.     long pixel[1];
  701.  
  702.     pixel[0] = texture->color.pixel;
  703.     /* dont free black/white pixels */
  704.     if (pixel[0]!=BlackPixelOfScreen(DefaultScreenOfDisplay(dpy))
  705.         && pixel[0]!=WhitePixelOfScreen(DefaultScreenOfDisplay(dpy)))
  706.         XFreeColors(dpy, DefaultColormap(dpy, scr), pixel, 1, 0);
  707.     }
  708.     if (texture->pixmap) {
  709.     XFreePixmap(dpy, texture->pixmap);
  710.     }
  711.     free(texture->spec);
  712.     free(texture);
  713. }
  714.  
  715.  
  716. void
  717. setupTexture(RContext *rc, BackgroundTexture **textures, int *maxTextures,
  718.          int workspace, char *texture)
  719. {
  720.     BackgroundTexture *newTexture = NULL;
  721.     int i;
  722.  
  723.     /* unset the texture */
  724.     if (!texture) {
  725.     if (textures[workspace]!=NULL) {
  726.         textures[workspace]->refcount--;
  727.  
  728.         if (textures[workspace]->refcount == 0)
  729.         freeTexture(textures[workspace]);
  730.     }
  731.     textures[workspace] = NULL;
  732.     return;
  733.     }
  734.  
  735.     if (textures[workspace] 
  736.     && strcasecmp(textures[workspace]->spec, texture)==0) {
  737.     /* texture did not change */
  738.     return;
  739.     }
  740.  
  741.     /* check if the same texture is already created */
  742.     for (i = 0; i < *maxTextures; i++) {
  743.     if (textures[i] && strcasecmp(textures[i]->spec, texture)==0) {
  744.         newTexture = textures[i];
  745.         break;
  746.     }
  747.     }
  748.  
  749.     if (!newTexture) {
  750.     /* create the texture */
  751.     newTexture = parseTexture(rc, texture);
  752.     }
  753.     if (!newTexture)
  754.     return;
  755.  
  756.     if (textures[workspace]!=NULL) {
  757.  
  758.     textures[workspace]->refcount--;
  759.  
  760.     if (textures[workspace]->refcount == 0)
  761.         freeTexture(textures[workspace]);
  762.     }
  763.  
  764.     newTexture->refcount++;
  765.     textures[workspace] = newTexture;
  766.  
  767.     if (*maxTextures < workspace)
  768.     *maxTextures = workspace;
  769. }
  770.  
  771.  
  772.  
  773. Pixmap
  774. duplicatePixmap(Pixmap pixmap, int width, int height)
  775. {
  776.     Display *tmpDpy;
  777.     Pixmap copyP;
  778.  
  779.     /* must open a new display or the RetainPermanent will
  780.      * leave stuff allocated in RContext unallocated after exit */
  781.     tmpDpy = XOpenDisplay(display);
  782.     if (!tmpDpy) {
  783.     wwarning("could not open display to update background image information");
  784.  
  785.     return None;
  786.     } else {
  787.     XSync(dpy, False);
  788.  
  789.     copyP = XCreatePixmap(tmpDpy, root, width, height,
  790.                    DefaultDepth(tmpDpy, scr));
  791.     XCopyArea(tmpDpy, pixmap, copyP, DefaultGC(tmpDpy, scr),
  792.           0, 0, width, height, 0, 0);
  793.     XSync(tmpDpy, False);
  794.  
  795.     XSetCloseDownMode(tmpDpy, RetainPermanent);
  796.     XCloseDisplay(tmpDpy);
  797.     }
  798.  
  799.     return copyP;
  800. }
  801.  
  802.  
  803. static int
  804. dummyErrorHandler(Display *dpy, XErrorEvent *err)
  805. {
  806.     return 0;
  807. }
  808.  
  809. void
  810. setPixmapProperty(Pixmap pixmap)
  811. {
  812.     static Atom prop = 0;
  813.     Atom type;
  814.     int format;
  815.     unsigned long length, after;
  816.     unsigned char *data;
  817.     int mode;
  818.     
  819.     if (!prop) {
  820.     prop = XInternAtom(dpy, "_XROOTPMAP_ID", False);
  821.     }
  822.  
  823.     XGrabServer(dpy);
  824.  
  825.     /* Clear out the old pixmap */
  826.     XGetWindowProperty(dpy, root, prop, 0L, 1L, False, AnyPropertyType,
  827.                        &type, &format, &length, &after, &data);
  828.  
  829.     if ((type == XA_PIXMAP) && (format == 32) && (length == 1)) {
  830.     XSetErrorHandler(dummyErrorHandler);
  831.         XKillClient(dpy, *((Pixmap *)data));
  832.     XSync(dpy, False);
  833.     XSetErrorHandler(NULL);
  834.     mode = PropModeReplace;
  835.     } else {
  836.     mode = PropModeAppend;
  837.     }
  838.     if (pixmap)
  839.     XChangeProperty(dpy, root, prop, XA_PIXMAP, 32, mode,
  840.             (unsigned char *) &pixmap, 1);
  841.     else
  842.     XDeleteProperty(dpy, root, prop);
  843.  
  844.  
  845.     XUngrabServer(dpy);
  846.     XFlush(dpy);
  847. }
  848.  
  849.  
  850.  
  851. void
  852. changeTexture(BackgroundTexture *texture)
  853. {
  854.     if (!texture) {
  855.     return;
  856.     }
  857.  
  858.     if (texture->solid) {
  859.     XSetWindowBackground(dpy, root, texture->color.pixel);
  860.     } else {
  861.     XSetWindowBackgroundPixmap(dpy, root, texture->pixmap);
  862.     }
  863.     XClearWindow(dpy, root);
  864.  
  865.     XSync(dpy, False);
  866.  
  867.     {
  868.     Pixmap pixmap;
  869.     
  870.     pixmap = duplicatePixmap(texture->pixmap, texture->width, 
  871.                  texture->height);
  872.  
  873.     setPixmapProperty(pixmap);
  874.     }
  875. }
  876.  
  877.  
  878. int
  879. readmsg(int fd, unsigned char *buffer, int size)
  880. {
  881.     int count;
  882.     
  883.     count = 0;
  884.     while (size>0) {
  885.     count = read(fd, buffer, size);
  886.     if (count < 0)
  887.         return -1;
  888.     size -= count;
  889.     buffer += count;
  890.     *buffer = 0;
  891.     }
  892.  
  893.     return size;
  894. }
  895.  
  896.  
  897. /*
  898.  * Message Format:
  899.  * sizeSntexture_spec - sets the texture for workspace n
  900.  * sizeCn - change background texture to the one for workspace n
  901.  * sizePpath - set the pixmap search path
  902.  * 
  903.  * n is 4 bytes
  904.  * size = 4 bytes for length of the message data
  905.  */
  906. void
  907. helperLoop(RContext *rc)
  908. {
  909.     BackgroundTexture *textures[WORKSPACE_COUNT];
  910.     int maxTextures = 0;
  911.     unsigned char buffer[2048], buf[8];
  912.     int size;
  913.     int errcount = 4;
  914.  
  915.     memset(textures, 0, WORKSPACE_COUNT*sizeof(BackgroundTexture*));
  916.  
  917.  
  918.     while (1) {
  919.     int workspace;
  920.  
  921.     /* get length of message */
  922.     if (readmsg(0, buffer, 4) < 0) {
  923.         wsyserror("error reading message from Window Maker");
  924.         errcount--;
  925.         if (errcount == 0) {
  926.         wfatal("quitting");
  927.         exit(1);
  928.         }
  929.         continue;
  930.     }
  931.     memcpy(buf, buffer, 4);
  932.     buf[4] = 0;
  933.     size = atoi(buf);
  934.  
  935.     /* get message */
  936.     if (readmsg(0, buffer, size) < 0) {
  937.         wsyserror("error reading message from Window Maker");
  938.         errcount--;
  939.         if (errcount == 0) {
  940.         wfatal("quitting");
  941.         exit(1);
  942.         }
  943.         continue;
  944.     }
  945. #ifdef DEBUG
  946.     printf("RECEIVED %s\n",buffer);
  947. #endif
  948.     if (buffer[0]!='P' && buffer[0]!='K') {
  949.         memcpy(buf, &buffer[1], 4);
  950.         buf[4] = 0;
  951.         workspace = atoi(buf);
  952.         if (workspace < 0 || workspace >= WORKSPACE_COUNT) {
  953.         wwarning("received message with invalid workspace number %i\n",
  954.              workspace);
  955.         continue;
  956.         }
  957.     }
  958.  
  959.     switch (buffer[0]) {
  960.      case 'S':
  961. #ifdef DEBUG
  962.         printf("set texture %s\n", &buffer[5]);
  963. #endif
  964.         setupTexture(rc, textures, &maxTextures, workspace, &buffer[5]);
  965.         break;
  966.  
  967.      case 'C':
  968. #ifdef DEBUG
  969.         printf("change texture %i\n", workspace);
  970. #endif
  971.         if (!textures[workspace]) {
  972.         changeTexture(textures[0]);
  973.         } else {
  974.         changeTexture(textures[workspace]);
  975.         }
  976.         break;
  977.  
  978.      case 'P':
  979. #ifdef DEBUG
  980.         printf("change pixmappath %s\n", &buffer[1]);
  981. #endif
  982.         if (PixmapPath)
  983.         free(PixmapPath);
  984.         PixmapPath = wstrdup(&buffer[1]);
  985.         break;
  986.  
  987.      case 'U':
  988. #ifdef DEBUG
  989.         printf("unset workspace %i\n", workspace);
  990. #endif
  991.         setupTexture(rc, textures, &maxTextures, workspace, NULL);
  992.         break;
  993.  
  994.      case 'K':
  995. #ifdef DEBUG
  996.         printf("exit command\n");
  997. #endif
  998.         exit(0);
  999.  
  1000.      default:
  1001.         wwarning("unknown message received");
  1002.         break;
  1003.     }
  1004.     }
  1005. }
  1006.  
  1007.  
  1008. void
  1009. updateDomain(char *domain, char *key, char *texture)
  1010. {
  1011.     char *program = "wdwrite";
  1012.  
  1013.     system(wstrappend("wdwrite ", 
  1014.               wstrappend(domain, smooth ? " SmoothWorkspaceBack YES"
  1015.                  : " SmoothWorkspaceBack NO")));
  1016.  
  1017.     execlp(program, program, domain, key, texture, NULL);
  1018.     wwarning("warning could not run \"%s\"", program);
  1019. }
  1020.  
  1021.  
  1022.  
  1023. char*
  1024. globalDefaultsPathForDomain(char *domain)
  1025. {
  1026.     char path[1024];
  1027.  
  1028.     sprintf(path, "%s/WindowMaker/%s", SYSCONFDIR, domain);
  1029.  
  1030.     return wstrdup(path);
  1031. }
  1032.  
  1033.  
  1034. proplist_t
  1035. getValueForKey(char *domain, char *keyName)
  1036. {
  1037.     char *path;
  1038.     proplist_t key;
  1039.     proplist_t d;
  1040.     proplist_t val;
  1041.  
  1042.     key = PLMakeString(keyName);
  1043.  
  1044.     /* try to find PixmapPath in user defaults */
  1045.     path = wdefaultspathfordomain(domain);
  1046.     d = PLGetProplistWithPath(path);
  1047.     if (!d) {
  1048.     wwarning("could not open domain file %s", path);
  1049.     }
  1050.     free(path);
  1051.  
  1052.     if (d && !PLIsDictionary(d)) {
  1053.     PLRelease(d);
  1054.     d = NULL;
  1055.     }
  1056.     if (d) {
  1057.     val = PLGetDictionaryEntry(d, key);
  1058.     } else {
  1059.     val = NULL;
  1060.     }
  1061.     /* try to find PixmapPath in global defaults */
  1062.     if (!val) {
  1063.     path = globalDefaultsPathForDomain(domain);
  1064.     if (!path) {
  1065.         wwarning("could not locate file for domain %s", domain);
  1066.         d = NULL;
  1067.     } else {
  1068.         d = PLGetProplistWithPath(path);
  1069.         free(path);
  1070.     }
  1071.  
  1072.     if (d && !PLIsDictionary(d)) {
  1073.         PLRelease(d);
  1074.         d = NULL;
  1075.     }
  1076.     if (d) {
  1077.         val = PLGetDictionaryEntry(d, key);
  1078.         
  1079.     } else {
  1080.         val = NULL;
  1081.     }
  1082.     }
  1083.  
  1084.     if (val)
  1085.     PLRetain(val);
  1086.  
  1087.     PLRelease(key);
  1088.     if (d)
  1089.     PLRelease(d);
  1090.  
  1091.     return val;
  1092. }
  1093.  
  1094.  
  1095.  
  1096. char*
  1097. getPixmapPath(char *domain)
  1098. {
  1099.     proplist_t val;
  1100.     char *ptr, *data;
  1101.     int len, i, count;
  1102.  
  1103.     val = getValueForKey(domain, "PixmapPath");
  1104.     
  1105.     if (!val || !PLIsArray(val)) {
  1106.     if (val)
  1107.         PLRelease(val);
  1108.     return wstrdup("");
  1109.     }
  1110.  
  1111.     count = PLGetNumberOfElements(val);
  1112.     len = 0;
  1113.     for (i=0; i<count; i++) {
  1114.     proplist_t v;
  1115.  
  1116.     v = PLGetArrayElement(val, i);
  1117.     if (!v || !PLIsString(v)) {
  1118.         continue;
  1119.     }
  1120.     len += strlen(PLGetString(v))+1;
  1121.     }
  1122.  
  1123.     ptr = data = wmalloc(len+1);
  1124.     *ptr = 0;
  1125.  
  1126.     for (i=0; i<count; i++) {
  1127.     proplist_t v;
  1128.  
  1129.     v = PLGetArrayElement(val, i);
  1130.     if (!v || !PLIsString(v)) {
  1131.         continue;
  1132.     }
  1133.     strcpy(ptr, PLGetString(v));
  1134.  
  1135.     ptr += strlen(PLGetString(v));
  1136.     *ptr = ':';
  1137.     ptr++;
  1138.     }
  1139.     if (i>0)
  1140.     ptr--; *(ptr--) = 0;
  1141.  
  1142.     PLRelease(val);
  1143.  
  1144.     return data;
  1145. }
  1146.  
  1147.  
  1148. char*
  1149. getFullPixmapPath(char *file)
  1150. {
  1151.     char *tmp;
  1152.  
  1153.     if (!PixmapPath || !(tmp = wfindfile(PixmapPath, file))) {
  1154.     int bsize = 512;
  1155.     char *path = wmalloc(bsize);
  1156.     
  1157.     while (!getcwd(path, bsize)) {
  1158.         free(path);
  1159.         bsize += bsize/2;
  1160.         path = malloc(bsize);
  1161.     }
  1162.  
  1163.     tmp = wstrappend(path, "/");
  1164.     free(path);
  1165.     path = wstrappend(tmp, file);
  1166.     free(tmp);
  1167.  
  1168.     return path;
  1169.     }
  1170.     
  1171.     /* the file is in the PixmapPath */
  1172.     free(tmp);
  1173.  
  1174.     return wstrdup(file);
  1175. }
  1176.  
  1177.  
  1178.  
  1179. void
  1180. wAbort()
  1181. {
  1182.     wfatal("aborting");
  1183.     exit(1);
  1184. }
  1185.  
  1186.  
  1187.  
  1188. void
  1189. print_help(char *ProgName)
  1190. {
  1191.     printf("Usage: %s [options] [image]\n", ProgName);
  1192.     puts("Sets the workspace background to the specified image or a texture and optionally update Window Maker configuration");
  1193.     puts("");
  1194. #define P(m) puts(m)
  1195. P(" -display             display to use");
  1196. P(" -d, --dither             dither image");
  1197. P(" -m, --match            match  colors");
  1198. P(" -S, --smooth            smooth scaled image");
  1199. P(" -b, --back-color <color>    background color");
  1200. P(" -t, --tile            tile   image");
  1201. P(" -e, --center            center image");
  1202. P(" -s, --scale            scale  image (default)");
  1203. P(" -a, --maxscale            scale  image and keep aspect ratio");
  1204. P(" -u, --update-wmaker        update WindowMaker domain database");
  1205. P(" -D, --update-domain <domain>    update <domain> database");
  1206. P(" -c, --colors <cpc>        colors per channel to use");
  1207. P(" -p, --parse <texture>        proplist style texture specification");
  1208. P(" -w, --workspace <workspace>    update background for the specified workspace");
  1209. P("     --version             show version of wmsetbg and exit");
  1210. P("     --help             show this help and exit");    
  1211. #undef P
  1212. }
  1213.  
  1214.  
  1215.  
  1216. void
  1217. changeTextureForWorkspace(char *domain, char *texture, int workspace)
  1218. {
  1219.     proplist_t array;
  1220.     proplist_t val;
  1221.     char *value;
  1222.     int j;
  1223.     
  1224.     val = PLGetProplistWithDescription(texture);
  1225.     if (!val) {
  1226.     wwarning("could not parse texture %s", texture);
  1227.     return;
  1228.     }
  1229.  
  1230.     array = getValueForKey("WindowMaker", "WorkspaceSpecificBack");
  1231.  
  1232.     if (!array) {
  1233.     array = PLMakeArrayFromElements(NULL, NULL);
  1234.     }
  1235.  
  1236.     j = PLGetNumberOfElements(array);
  1237.     if (workspace >= j) {
  1238.     proplist_t empty;
  1239.  
  1240.     empty = PLMakeArrayFromElements(NULL, NULL);
  1241.  
  1242.     while (j++ < workspace-1) {
  1243.         PLAppendArrayElement(array, empty);
  1244.     }
  1245.     PLAppendArrayElement(array, val);
  1246.     } else {
  1247.     PLRemoveArrayElement(array, workspace);
  1248.     PLInsertArrayElement(array, val, workspace);
  1249.     }
  1250.  
  1251.     value = PLGetDescription(array);
  1252.     updateDomain(domain, "WorkspaceSpecificBack", value);
  1253. }
  1254.  
  1255.  
  1256. int
  1257. main(int argc, char **argv)
  1258. {
  1259.     int i;
  1260.     int helperMode = 0;
  1261.     RContext *rc;
  1262.     RContextAttributes rattr;
  1263.     char *style = "spixmap";
  1264.     char *back_color = "gray20";
  1265.     char *image_name = NULL;
  1266.     char *domain = "WindowMaker";
  1267.     int update=0, cpc=4, render_mode=RDitheredRendering, obey_user=0;
  1268.     char *texture = NULL;
  1269.     int workspace = -1;
  1270.     
  1271.     signal(SIGINT, SIG_DFL);
  1272.     signal(SIGTERM, SIG_DFL);
  1273.     signal(SIGQUIT, SIG_DFL);
  1274.     signal(SIGSEGV, SIG_DFL);
  1275.     signal(SIGBUS, SIG_DFL);
  1276.     signal(SIGFPE, SIG_DFL);
  1277.     signal(SIGABRT, SIG_DFL);
  1278.     signal(SIGHUP, SIG_DFL);
  1279.     signal(SIGPIPE, SIG_DFL);
  1280.     signal(SIGCHLD, SIG_DFL);
  1281.     
  1282.     WMInitializeApplication("wmsetbg", &argc, argv);
  1283.     
  1284.     for (i=1; i<argc; i++) {
  1285.     if (strcmp(argv[i], "-helper")==0) {
  1286.         helperMode = 1;
  1287.     } else if (strcmp(argv[i], "-display")==0) {
  1288.         i++;
  1289.         if (i>=argc) {
  1290.         wfatal("too few arguments for %s\n", argv[i-1]);
  1291.         exit(1);
  1292.         }
  1293.         display = argv[i];
  1294.     } else if (strcmp(argv[i], "-s")==0
  1295.            || strcmp(argv[i], "--scale")==0) {
  1296.         style = "spixmap";
  1297.     } else if (strcmp(argv[i], "-t")==0
  1298.            || strcmp(argv[i], "--tile")==0) {
  1299.         style = "tpixmap";
  1300.     } else if (strcmp(argv[i], "-e")==0
  1301.            || strcmp(argv[i], "--center")==0) {
  1302.         style = "cpixmap";
  1303.     } else if (strcmp(argv[i], "-a")==0
  1304.            || strcmp(argv[i], "--maxscale")==0) {
  1305.         style = "mpixmap";        
  1306.     } else if (strcmp(argv[i], "-d")==0
  1307.            || strcmp(argv[i], "--dither")==0) {
  1308.         render_mode = RDitheredRendering;
  1309.         obey_user++;
  1310.     } else if (strcmp(argv[i], "-m")==0
  1311.            || strcmp(argv[i], "--match")==0) {
  1312.         render_mode = RBestMatchRendering;
  1313.         obey_user++;
  1314.     } else if (strcmp(argv[i], "-S")==0
  1315.            || strcmp(argv[i], "--smooth")==0) {
  1316.         smooth = True;
  1317.     } else if (strcmp(argv[i], "-u")==0
  1318.            || strcmp(argv[i], "--update-wmaker")==0) {
  1319.         update++;
  1320.     } else if (strcmp(argv[i], "-D")==0
  1321.            || strcmp(argv[i], "--update-domain")==0) {
  1322.         update++;
  1323.         i++;
  1324.         if (i>=argc) {
  1325.         wfatal("too few arguments for %s\n", argv[i-1]);
  1326.         exit(1);
  1327.         }
  1328.         domain = wstrdup(argv[i]);
  1329.     } else if (strcmp(argv[i], "-c")==0
  1330.            || strcmp(argv[i], "--colors")==0) {
  1331.         i++;
  1332.         if (i>=argc) {
  1333.         wfatal("too few arguments for %s\n", argv[i-1]);
  1334.         exit(1);
  1335.         }
  1336.         if (sscanf(argv[i], "%i", &cpc)!=1) {
  1337.         wfatal("bad value for colors per channel: \"%s\"\n", argv[i]);
  1338.         exit(1);
  1339.         }
  1340.     } else if (strcmp(argv[i], "-b")==0
  1341.            || strcmp(argv[i], "--back-color")==0) {
  1342.         i++;
  1343.         if (i>=argc) {
  1344.         wfatal("too few arguments for %s\n", argv[i-1]);
  1345.         exit(1);
  1346.         }
  1347.         back_color = argv[i];
  1348.     } else if (strcmp(argv[i], "-p")==0
  1349.            || strcmp(argv[i], "--parse")==0) {
  1350.         i++;
  1351.         if (i>=argc) {
  1352.         wfatal("too few arguments for %s\n", argv[i-1]);
  1353.         exit(1);
  1354.         }
  1355.         texture = argv[i];
  1356.     } else if (strcmp(argv[i], "-w")==0
  1357.            || strcmp(argv[i], "--workspace")==0) {
  1358.         i++;
  1359.         if (i>=argc) {
  1360.         wfatal("too few arguments for %s\n", argv[i-1]);
  1361.         exit(1);
  1362.         }
  1363.         if (sscanf(argv[i], "%i", &workspace)!=1) {
  1364.         wfatal("bad value for workspace number: \"%s\"", 
  1365.             argv[i]);
  1366.         exit(1);
  1367.         }
  1368.     } else if (strcmp(argv[i], "--version")==0) {
  1369.  
  1370.         printf(PROG_VERSION);
  1371.         exit(0);
  1372.  
  1373.     } else if (strcmp(argv[i], "--help")==0) {
  1374.         print_help(argv[0]);
  1375.         exit(0);
  1376.     } else if (argv[i][0] != '-') {
  1377.         image_name = argv[i];
  1378.     } else {
  1379.         printf("%s: invalid argument '%s'\n", argv[0], argv[i]);
  1380.         printf("Try '%s --help' for more information\n", argv[0]);
  1381.         exit(1);
  1382.     }
  1383.     }
  1384.     if (!image_name && !texture && !helperMode) {
  1385.     printf("%s: you must specify a image file name or a texture\n", 
  1386.            argv[0]);
  1387.     printf("Try '%s --help' for more information\n", argv[0]);
  1388.     exit(1);
  1389.     }
  1390.  
  1391.     
  1392.     PixmapPath = getPixmapPath(domain);
  1393.     if (!smooth) {
  1394.     proplist_t val;
  1395. #if 0 /* some problem with Alpha... TODO: check if its right */
  1396.     val = PLGetDictionaryEntry(domain, 
  1397.                    PLMakeString("SmoothWorkspaceBack"));
  1398. #else
  1399.     val = getValueForKey(domain, "SmoothWorkspaceBack");
  1400. #endif
  1401.  
  1402.     if (val && PLIsString(val) && strcasecmp(PLGetString(val), "YES")==0)
  1403.         smooth = True;
  1404.     }
  1405.  
  1406.     dpy = XOpenDisplay(display);
  1407.     if (!dpy) {
  1408.     wfatal("could not open display");
  1409.     exit(1);
  1410.     }
  1411. #if 0
  1412.     XSynchronize(dpy, 1);
  1413. #endif
  1414.  
  1415.     root = DefaultRootWindow(dpy);
  1416.  
  1417.     scr = DefaultScreen(dpy);
  1418.     
  1419.     scrWidth = WidthOfScreen(DefaultScreenOfDisplay(dpy));
  1420.     scrHeight = HeightOfScreen(DefaultScreenOfDisplay(dpy));
  1421.  
  1422.     if (!obey_user && DefaultDepth(dpy, scr) <= 8)
  1423.         render_mode = RDitheredRendering;
  1424.  
  1425.     rattr.flags = RC_RenderMode | RC_ColorsPerChannel
  1426.     | RC_StandardColormap;
  1427.     rattr.render_mode = render_mode;
  1428.     rattr.colors_per_channel = cpc;
  1429.     rattr.standard_colormap_mode = RCreateStdColormap;
  1430.  
  1431.     rc = RCreateContext(dpy, scr, &rattr);
  1432.     if (!rc) {
  1433.     wfatal("could not initialize wrlib:",
  1434.            RMessageForError(RErrorCode));
  1435.     exit(1);
  1436.     }
  1437.  
  1438.     if (helperMode) {
  1439.     /* lower priority, so that it wont use all the CPU */
  1440.     nice(1000);
  1441.  
  1442.     helperLoop(rc);
  1443.     } else {
  1444.     BackgroundTexture *tex;
  1445.     char buffer[4098];
  1446.  
  1447.     if (!texture) {
  1448.         char *image_path = getFullPixmapPath(image_name);
  1449.         
  1450.         sprintf(buffer, "(%s, \"%s\", %s)", style, image_path, back_color);
  1451.         free(image_path);
  1452.         texture = (char*)buffer;
  1453.     }
  1454.  
  1455.     if (update && workspace < 0) {
  1456.         updateDomain(domain, "WorkspaceBack", texture);
  1457.     }
  1458.  
  1459.     tex = parseTexture(rc, texture);
  1460.     if (!tex)
  1461.         exit(1);
  1462.  
  1463.     if (workspace<0)
  1464.         changeTexture(tex);
  1465.     else {
  1466.         /* always update domain */
  1467.         changeTextureForWorkspace(domain, texture, workspace);
  1468.     }
  1469.     }
  1470.  
  1471.     return 0;
  1472. }
  1473.  
  1474.